package com.xixibaby.message;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.xixibaby.core.Assert;
import com.xixibaby.core.message.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

/**
 * 基础执行器实现类
 * @param <T>
 */
@Slf4j
public class ExecuteHandler<T extends ExeObj> implements Excute<T> {

    @Autowired
    private AsynExcute<T> asynExcute;

    @Override
    public void excuteByTime(Date date, ChannelGroup<T> context, T object) {
        //List<Channel<T>> channels = context.channels();
       // channels.forEach(x -> this.excuteByTime(date,x,object));
        List<Channel<T>> channels = context.channels();
        for (int i = 0; i < channels.size(); i++) {
            this.excute(date,channels.get(i) ,object);
        }
    }

    @Override
    public void excuteByTime(Date date, Channel<T> context, T object) {
        context.sendDate(date);
        this.excute(context,object);
    }

    @Override
    public void excute(Date delay, Channel<T> context, T object) {
        context.delay().setDate(delay);
        this.excute(context,object);
    }

    @Override
    public void excute(Date delay, ChannelGroup<T> context, T object) {
        List<Channel<T>> channels = context.channels();
        for (int i = 0; i < channels.size(); i++) {
            this.excute(delay,channels.get(i) ,object);
        }
        //context.channels().forEach(x -> this.excute(delay,x,object));
    }

    @Override
    public void excute(ChannelGroup<T> context, T object) {
        List<Channel<T>> channels = context.channels();
        for (int i = 0; i < channels.size(); i++) {
            this.excute(channels.get(i) ,object);
        }
    }

    /**
     * 执行具体发送之前 会处理发送目标方案
     * 三种处理方案
     * 1 object.getTarget();
     * 2 channal 指定从obj的param里面获取某个字段 需要提供字段名称
     * 3 channal 动态获取 需要提供动态获取函数
     * @param channel
     * @param object
     * @return
     */
    @Override
    public List<Boolean> excute(Channel<T> channel, final T object) {
        T obj = ObjectUtil.clone(object);
        if(Assert.notEmpty(channel.target())){
            if(channel.isDaymic()){
                String strings = channel.daymicTarget().target(object.getParams());
                obj.setTarget(strings.split(","));
            }else{
                Map<String, Object> objectMap = Convert.toMap(String.class, Object.class, object.getParams());
                Object o = objectMap.get(channel.target());
                Assert.succ(o).thenThrow("指定的目标值不存在[{}]",channel.target());
                String[] newTar = new String[]{o.toString()};
                obj.setTarget(newTar);
            }
        }else{
            obj.setTarget(object.getTarget());
        }

        if(channel.aysn() && asynExcute.support()){
            //如果是异步执行 引入异步执行器
            this.log(channel,object,obj.getTarget(),channel.id());
            asynExcute.excute(channel.seconds(), channel, object);
            return Collections.singletonList(true);
        }else{
            return channel.handler(obj.getTarget(), object.getParams());
        }

    }

    private void log(Channel<T> channel, T obj, String[] target, String id){
        this.log(target,channel.getClass().getSimpleName(),
                DateUtil.format(channel.sendDate(), DatePattern.NORM_DATETIME_FORMAT),
                channel.seconds(),
                DateUtil.format(channel.delay().getDate(), DatePattern.NORM_DATETIME_FORMAT)
                ,channel.delay().getDelay(),obj,id);
    }

    protected void log(Object[] target, String channelName, String sendDate, Integer seconds, String baseDate, Integer offsetSeconds, T obj, String id){
        log.info("消息发送: 目标：[{}]", StrUtil.join(",", target));
        log.info("消息发送:通道名称【{}】发送时间【{}】延时秒数【{}】基础时间【{}】偏移时间【{}】", channelName, sendDate, seconds, baseDate ,offsetSeconds);
        log.info("消息发送: 消息内容【{}】", JSONObject.toJSONString(obj));
    }

}
